package com.itedge.solutionmanager.web.controller.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.itedge.solutionmanager.constants.SolutionManagerConstants;
import com.itedge.solutionmanager.domain.impl.Employee;
import com.itedge.solutionmanager.domain.impl.EmployeeAuthority;
import com.itedge.solutionmanager.domain.dto.EmployeeDto;
import com.itedge.solutionmanager.util.StringUtil;
import com.itedge.infrastructure.service.domain.IEntityService;
import com.itedge.infrastructure.service.domain.ISearchableEntityService;
import com.itedge.infrastructure.util.WebUtil;
import com.itedge.infrastructure.web.controller.impl.AbstractEntityController;

@RequestMapping("/useradmin")
@Controller
public class UserAdminController extends AbstractEntityController<Employee> {

    private ISearchableEntityService<Employee> employeeService;   
    private IEntityService<EmployeeAuthority> employeeAuthorityService;
    private PasswordEncoder passwordEncoder;

    @Autowired
    protected UserAdminController(ISearchableEntityService<Employee> employeeService,
    		IEntityService<EmployeeAuthority> employeeAuthorityService, PasswordEncoder passwordEncoder) {
		super(employeeService);
		this.employeeService = employeeService;
		this.employeeAuthorityService = employeeAuthorityService;
		this.passwordEncoder = passwordEncoder;
	}    
    
	@Override
	public String getModelKeyForEntitiesList() {	
		return "employees";
	}
    
	@Override
	public String getListView() {
		return "useradmin/list";
	}

	@Override
	public int getDefaultPageSizeForListView() {
		return SolutionManagerConstants.DEFAULT_SIZE_PER_PAGE;
	}
    
	@RequestMapping(method = RequestMethod.POST)
    public String create(@Valid Employee employee, BindingResult result, Model model, HttpServletRequest request) {
        if (result.hasErrors()) {
            model.addAttribute("employee", employee);
            return "useradmin/create";
        }
        // encode password - without salt value (second argument)
        employee.setPassword(passwordEncoder.encodePassword(employee.getPassword(), null));
        // employee is enabled by default
        employee.setEnabled(true);
        bindRoles(employee,request);
        employeeService.persist(employee);
        return "redirect:/useradmin/" + WebUtil.encodeUrlPathSegment(employee.getId().toString(), request);
    }
    
	@RequestMapping(params = "form", method = RequestMethod.GET)
    public String createForm(Model model) {
        model.addAttribute("employee", new Employee());
        return "useradmin/create";
    }
	
	@RequestMapping(method = RequestMethod.PUT)
    public String edit(@Valid Employee employee, BindingResult result, Model model, HttpServletRequest request) {
        if (result.hasErrors()) {
            model.addAttribute("employee", employee);
            return "useradmin/edit";
        }
        bindRoles(employee,request);
        Employee toUpdate = employeeService.findEntity(employee.getId());
    	toUpdate.getAddress().setEmail(employee.getAddress().getEmail());
    	toUpdate.setUsername(employee.getUsername());
    	toUpdate.setFirstName(employee.getFirstName());
    	toUpdate.setSecondName(employee.getSecondName());
        toUpdate.setEmplAuthorities(employee.getEmplAuthorities());
        toUpdate.setEnabled(employee.isEnabled());
        employeeService.merge(toUpdate);
        return "redirect:/useradmin/" + WebUtil.encodeUrlPathSegment(employee.getId().toString(), request);
    }	
	
	@RequestMapping(value = "/{id}", params = "form", method = RequestMethod.GET)
    public String edit(@PathVariable("id") Long id, Model model) {
        Employee employee = employeeService.findEntity(id);
        model.addAttribute("assignedIds", WebUtil.getIdsStringFromEntities(employee.getEmplAuthorities()));
		model.addAttribute("employee", employee);
        return "useradmin/edit";
    }
    
	@RequestMapping(params = "searchForm", method = RequestMethod.GET)
    public String searchForm(Model model) {
        return "useradmin/search";
    } 	
	
	@RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public String show(@PathVariable("id") Long id, Model model) {
        Employee employee = employeeService.findEntity(id); 
        model.addAttribute("itemId", id);
		model.addAttribute("employee", employee);
        return "useradmin/show";
    }
	
	/*
	 * Method used for AJAX search requests on users, returning data in JSON format
	 */
	@RequestMapping(params = "searchForm", method = RequestMethod.POST, headers = "Accept=application/json")
    public @ResponseBody List<EmployeeDto> searchAsyncForUsers(@RequestParam(value = "searchName") String searchName,
    	    @RequestParam(value = "maxResults", required = false) Integer maxResults, HttpServletRequest request) {			
        Employee searchEmployee = new Employee();
        searchEmployee.setUsername(searchName);
        Iterator<Employee> usersIt = employeeService.findEntitiesByCriteria(searchEmployee, maxResults).iterator();
        List<EmployeeDto> employeeDtoList = new ArrayList<EmployeeDto>();
        while(usersIt.hasNext()) {
        	employeeDtoList.add(new EmployeeDto(usersIt.next()));
        }
        return employeeDtoList;
    }
	
	@ModelAttribute("employeeAuthorities")
    public Collection<EmployeeAuthority> populateAuthorities() {
        return employeeAuthorityService.findAllEntities();
    }
	
	private void bindRoles(Employee employee, HttpServletRequest request) {
		String paramString = request.getParameter("authorities_noBind");
		if (!StringUtil.isEmpty(paramString)) {
	    	List<String> assignedIdsList = Arrays.asList(paramString.split(","));
	    	Set<EmployeeAuthority> assignedAuthorities = new HashSet<EmployeeAuthority>();
	    	for(String id : assignedIdsList) {
	    		EmployeeAuthority authority = employeeAuthorityService.findEntity(new Long(id));
	    		assignedAuthorities.add(authority);
	    	}
	    	employee.setEmplAuthorities(assignedAuthorities);
		}
	}

}
